package com.laolang.pluto.module.generator.logic.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.laolang.pluto.common.core.domain.common.Page;
import com.laolang.pluto.common.exception.BusinessException;
import com.laolang.pluto.common.logic.impl.BaseLogicImpl;
import com.laolang.pluto.common.util.AssertUtil;
import com.laolang.pluto.common.util.CommonUtil;
import com.laolang.pluto.module.generator.component.GenComponent;
import com.laolang.pluto.module.generator.config.GenConfig;
import com.laolang.pluto.module.generator.consts.entity.GenTableConst;
import com.laolang.pluto.module.generator.consts.logic.GenBizCode;
import com.laolang.pluto.module.generator.entity.GenTable;
import com.laolang.pluto.module.generator.entity.GenTableColumn;
import com.laolang.pluto.module.generator.gen.GenInfo;
import com.laolang.pluto.module.generator.logic.GenLogic;
import com.laolang.pluto.module.generator.mapstruct.GenTableMapperStruct;
import com.laolang.pluto.module.generator.pojo.dto.GenTableUpdateBaseInfoDto;
import com.laolang.pluto.module.generator.pojo.dto.GenTableUpdateColumnInfoDto;
import com.laolang.pluto.module.generator.pojo.dto.GenTableUpdateGenInfoDto;
import com.laolang.pluto.module.generator.pojo.dto.TableInfoDto;
import com.laolang.pluto.module.generator.pojo.dto.TableListDto;
import com.laolang.pluto.module.generator.pojo.po.TableDetailPo;
import com.laolang.pluto.module.generator.pojo.po.TableInfoPo;
import com.laolang.pluto.module.generator.pojo.vo.GenTableDetailVo;
import com.laolang.pluto.module.generator.pojo.vo.GenTableVo;
import com.laolang.pluto.module.generator.service.GenTableColumnService;
import com.laolang.pluto.module.generator.service.GenTableService;
import com.laolang.pluto.module.generator.util.GenUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author laolang
 * @date 2021-08-01 16:35
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class GenLogicImpl extends BaseLogicImpl implements GenLogic {

    private final GenTableService genTableService;

    private final GenTableColumnService genTableColumnService;

    private final GenTableMapperStruct genTableMapperStruct;

    private final GenConfig genConfig;

    private final GenComponent genComponent;


    @Override
    public Page<GenTableVo> tableList(TableListDto dto) {
        return pageInfo2Page(genTableService.selectTableList(dto.getPage(), dto.getSize(), dto.getTableName(),
                dto.getTableComment(),
                dto.getStartDate(), dto.getEndDate()), genTableMapperStruct::entity2vo);
    }

    @Override
    public Page<TableInfoPo> tableInfoList(TableInfoDto dto) {
        genTableService.selectTableDetail("as_project");
        return pageInfo2Page(genTableService.selectTableInfoList(dto.getPage(), dto.getSize(),
                dto.getTableName(), dto.getTableComment()));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean addGenTable(String tableName) {
        TableInfoPo tableInfoPo = genTableService.selectTableInfoByTableName(tableName);
        /* 表不存在 */
        if (null == tableInfoPo) {
            throw new BusinessException(GenBizCode.NO_TABLE);
        }

        /* 代码生成列表已经存在 */
        int count = genTableService.count(Wrappers.<GenTable>lambdaQuery().eq(GenTable::getTableName, tableName));
        if (count > 0) {
            throw new BusinessException(GenBizCode.GEN_TABLE_EXIST);
        }

        /* 构造初始化代码生成信息 */
        GenTable insert = new GenTable();
        insert.setTableName(tableInfoPo.getTableName());
        insert.setTableComment(tableInfoPo.getTableComment());
        insert.setAuthor(genConfig.getAuthor());
        insert.setPackageName(genConfig.getPackageName());
        insert.setClassName(GenUtil.underline2UpperHump(tableInfoPo.getTableName()));
        insert.setWebUrl(tableName);
        insert.setGenPath(genConfig.getGenPath());
        insert.setGenType(GenTableConst.GenType.PATH.getValue());

        /* 保存代码生成基本信息 */
        genTableService.save(insert);

        /* 保存代码生成详细信息 */
        List<TableDetailPo> tableDetailPos = genTableService.selectTableDetail(tableInfoPo.getTableName());
        List<GenTableColumn> columnsInsert;
        columnsInsert = tableDetailPos.stream().map(po -> {
            GenTableColumn column = new GenTableColumn();
            column.setGenTableId(insert.getId());
            column.setColumnName(po.getField());
            column.setColumnComment(po.getComment());
            column.setColumnType(po.getType());
            column.setJavaType(GenUtil.mysqlType2javaType(po.getType()));
            column.setJavaField(GenUtil.underline2LowerHump(po.getField()));
            return column;
        }).collect(Collectors.toList());
        genTableColumnService.saveBatch(columnsInsert);

        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean removeGenTable(Long id) {
        genTableService.getById(id);
        /* 代码生成列表中不存在 */
        AssertUtil.notNull(log, genTableService.getById(id), GenBizCode.GEN_TABLE_NOT_EXIST,
                StrUtil.format("未查询到对应的表信息,id:{}", id));

        /* 删除详细信息 */
        genTableColumnService.remove(Wrappers.<GenTableColumn>lambdaUpdate().eq(GenTableColumn::getGenTableId, id));

        /* 删除 */
        genTableService.removeById(id);
        return null;
    }

    @Override
    public GenTableDetailVo genTableDetail(Long id) {
        GenTableDetailVo vo = new GenTableDetailVo();

        GenTable genTable = AssertUtil.notNull(log, genTableService.getById(id), GenBizCode.GEN_TABLE_NOT_EXIST,
                StrUtil.format("未查询到对应的表信息,id:{}", id));

        /* 基本信息 */
        GenTableDetailVo.BaseInfoBean baseInfoBean = new GenTableDetailVo.BaseInfoBean();
        vo.setBaseInfo(baseInfoBean);
        baseInfoBean.setId(genTable.getId());
        baseInfoBean.setTableName(genTable.getTableName());
        baseInfoBean.setTableComment(genTable.getTableComment());
        baseInfoBean.setClassName(genTable.getClassName());
        baseInfoBean.setWebUrl(genTable.getWebUrl());
        baseInfoBean.setAuthor(genTable.getAuthor());
        baseInfoBean.setRemark(genTable.getRemark());
        vo.setBaseInfo(baseInfoBean);

        /* 列信息 */
        List<GenTableDetailVo.ColumnInfoBean> columnInfoList = new ArrayList<>();
        vo.setColumnInfoList(columnInfoList);
        List<GenTableColumn> tableColumns = genTableColumnService.listByGenTableId(id);
        if (CollUtil.isNotEmpty(tableColumns)) {
            columnInfoList = tableColumns.stream().map(genTableColumn -> {
                GenTableDetailVo.ColumnInfoBean columnInfo = new GenTableDetailVo.ColumnInfoBean();
                columnInfo.setId(genTableColumn.getId());
                columnInfo.setColumnName(genTableColumn.getColumnName());
                columnInfo.setColumnComment(genTableColumn.getColumnComment());
                columnInfo.setColumnType(genTableColumn.getColumnType());
                columnInfo.setJavaType(genTableColumn.getJavaType());
                columnInfo.setJavaField(genTableColumn.getJavaField());
                return columnInfo;
            }).collect(Collectors.toList());
            vo.setColumnInfoList(columnInfoList);
        }

        /* 生成信息 */
        GenTableDetailVo.GenInfoBean genInfo = new GenTableDetailVo.GenInfoBean();
        vo.setGenInfo(genInfo);
        genInfo.setPackageName(genTable.getPackageName());
        genInfo.setGenType(genTable.getGenType());

        return vo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean updateGenTableBaseInfo(GenTableUpdateBaseInfoDto dto) {
        GenTable entity = AssertUtil.notNull(log, genTableService.getById(dto.getId()), GenBizCode.GEN_TABLE_NOT_EXIST,
                StrUtil.format("未查询到对应的表信息,id:{}", dto.getId()));

        if (StrUtil.isNotBlank(dto.getAuthor()) && !StrUtil.equals(entity.getAuthor(), dto.getAuthor())) {
            entity.setAuthor(dto.getAuthor());
        }
        // TODO 类名检查
        if (StrUtil.isNotBlank(dto.getClassName()) && !StrUtil.equals(entity.getClassName(), dto.getClassName())) {
            entity.setClassName(dto.getClassName());
        }

        entity.setRemark(dto.getRemark());

        return genTableService.updateById(entity);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean updateGenTableColumn(GenTableUpdateColumnInfoDto dto) {
        AssertUtil.notNull(log, genTableService.getById(dto.getGenTableId()), GenBizCode.GEN_TABLE_NOT_EXIST,
                StrUtil.format("未查询到对应的表信息,id:{}", dto.getGenTableId()));

        List<GenTableUpdateColumnInfoDto.ColumnInfoBean> columnInfoList = dto.getColumnInfoList();
        if (CollUtil.isEmpty(columnInfoList)) {
            return true;
        }

        List<Long> idList =
                columnInfoList.stream().map(GenTableUpdateColumnInfoDto.ColumnInfoBean::getId).collect(Collectors.toList());
        List<GenTableColumn> entityList = genTableColumnService.listByIds(idList);
        if (CollUtil.isEmpty(entityList)) {
            return true;
        }

        Map<Long, GenTableUpdateColumnInfoDto.ColumnInfoBean> columnInfoBeanMap =
                columnInfoList.stream().collect(Collectors.toMap(GenTableUpdateColumnInfoDto.ColumnInfoBean::getId,
                        columnInfoBean -> columnInfoBean));

        int updateCount = 0;
        for (GenTableColumn entity : entityList) {
            GenTableUpdateColumnInfoDto.ColumnInfoBean bean = columnInfoBeanMap.get(entity.getId());
            int i = 0;
            // TODO java 字段名检查
            if (StrUtil.isNotBlank(bean.getJavaField()) && !StrUtil.equals(entity.getJavaField(),
                    bean.getJavaField())) {
                i++;
                entity.setJavaField(bean.getJavaField());
            }
            // TODO java 类型名检查
            if (StrUtil.isNotBlank(bean.getJavaType()) && !StrUtil.equals(entity.getJavaType(), bean.getJavaType())) {
                i++;
                entity.setJavaType(bean.getJavaType());
            }
            updateCount = i > 0 ? updateCount + 1 : updateCount;
        }

        return updateCount <= 0 || genTableColumnService.updateBatchById(entityList);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean updateGenTableGenInfo(GenTableUpdateGenInfoDto dto) {

        AssertUtil.isTrue(log, CommonUtil.enumHasValue(GenTableConst.GenType.class, dto.getGenType()),
                GenBizCode.ERROR_GEN_TYPE, StrUtil.format("代码生成方式不正确:{}", JSONUtil.toJsonStr(dto)));

        GenTable entity = AssertUtil.notNull(log, genTableService.getById(dto.getGenTableId()),
                GenBizCode.GEN_TABLE_NOT_EXIST,
                StrUtil.format("未查询到对应的表信息,id:{}", dto.getGenTableId()));

        int updateCount = 0;

        // TODO 包名检查
        if (StrUtil.isNotBlank(dto.getPackageName()) && !StrUtil.equals(entity.getPackageName(),
                dto.getPackageName())) {
            entity.setPackageName(dto.getPackageName());
            updateCount++;
        }

        if (!dto.getGenType().equals(entity.getGenType())) {
            entity.setGenType(dto.getGenType());
            updateCount++;
        }

        return updateCount <= 0 || genTableService.updateById(entity);
    }

    @Override
    public Boolean genCode(Long id) {
        GenTable genTable = AssertUtil.notNull(log, genTableService.getById(id), GenBizCode.GEN_TABLE_NOT_EXIST,
                StrUtil.format("未查询到对应的表信息,id:{}", id));
        GenInfo genInfo = new GenInfo();
        GenInfo.BaseInfoBean baseInfoBean = new GenInfo.BaseInfoBean();
        baseInfoBean.setTableName(genTable.getTableName());
        baseInfoBean.setTableComment(genTable.getTableComment());
        baseInfoBean.setClassName(genTable.getClassName());

        baseInfoBean.setAuthor(genTable.getAuthor());
        baseInfoBean.setRemark(genTable.getRemark());
        baseInfoBean.setWebUrl(genTable.getWebUrl());
        genInfo.setBaseInfo(baseInfoBean);
        GenInfo.GenInfoBean genInfoBean = new GenInfo.GenInfoBean();
        genInfoBean.setPackageName(genTable.getPackageName());
        genInfoBean.setGenType(genTable.getGenType());
        genInfo.setGenInfo(genInfoBean);

        List<GenInfo.ColumnInfoBean> columnInfoList = new ArrayList<>();
        genInfo.setColumnInfoList(columnInfoList);

        List<GenTableColumn> columns = genTableColumnService.listByGenTableId(id);
        if (CollUtil.isNotEmpty(columns)) {
            columnInfoList = columns.stream().filter(genTableColumn -> !"id".equals(genTableColumn.getColumnName()) &&
                    !"create_by".equals(genTableColumn.getColumnName()) &&
                    !"create_time".equals(genTableColumn.getColumnName()) &&
                    !"update_by".equals(genTableColumn.getColumnName()) &&
                    !"update_time".equals(genTableColumn.getColumnName()) &&
                    !"version".equals(genTableColumn.getColumnName())).map(genTableColumn -> {
                GenInfo.ColumnInfoBean columnInfoBean = new GenInfo.ColumnInfoBean();
                columnInfoBean.setId(genTableColumn.getId());
                columnInfoBean.setColumnName(genTableColumn.getColumnName());
                columnInfoBean.setColumnComment(genTableColumn.getColumnComment());
                columnInfoBean.setColumnType(genTableColumn.getColumnType());
                columnInfoBean.setJavaType(genTableColumn.getJavaType());
                columnInfoBean.setJavaField(genTableColumn.getJavaField());
                return columnInfoBean;
            }).collect(Collectors.toList());
            genInfo.setColumnInfoList(columnInfoList);
        }

        genComponent.gen(genInfo);
        return true;
    }
}
